import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateRoleDto } from './dto/create-role.dto';
import { CreateAuthDto } from './dto/create-auth.dto';
import { Role } from './entities/role.entity';
import { Auth } from './entities/auth.entity';
import { RoleAdmin } from 'src/admin/entities/roleAdmin.entity';
import { Menu } from 'src/menu/entities/menu.entity';
import { Action } from 'src/menu/entities/action.entity';
import { DataSource, In, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { throwCustomException } from 'src/utils/fun';
@Injectable()
export class RoleService {
  constructor(
      @InjectRepository(Role)
      private readonly roleRepository: Repository<Role>,
      @InjectRepository(Auth)
      private readonly authRepository: Repository<Auth>,
      @InjectRepository(RoleAdmin)
      private readonly roleAdminRepository: Repository<RoleAdmin>,
      @InjectRepository(Menu)
      private readonly menuRepository: Repository<Menu>,
      @InjectRepository(Action)
      private readonly actionRepository: Repository<Action>,
      private readonly dataSource: DataSource,
      //@Inject(CACHE_MANAGER) private readonly cacheManager: Cache
    ) {}
  async isRoleExists(obj){
    const result = await this.roleRepository.findOne({ 
      where: obj
    });
    return !!result
  }
  /**
   * 创建角色
   * 
   * 此函数用于接收一个CreateRoleDto对象作为参数，尝试在数据库中创建一个新的角色条目如果角色名称已存在且未提供ID，
   * 则抛出异常阻止创建，以确保角色名称的唯一性如果角色名称不存在或提供了ID进行更新，则保存数据到数据库
   * 
   * @param createRoleDto 包含要创建或更新的角色信息的对象
   * @returns 返回保存到数据库中的角色实体
   * @throws 如果角色名称重复且未提供ID，或数据库操作失败，则抛出HttpException
   */
  async create(createRoleDto: CreateRoleDto) {
    try{
      const isExists = await this.isRoleExists({roleName: createRoleDto.roleName})
      if(isExists && !createRoleDto.id){
        throwCustomException('角色名称不可重复')
      }
      return await this.roleRepository.save({
        ...createRoleDto
      })
    } catch (error) {
      throw new HttpException(error.message, error.status, {
        
        cause: error
      });
    }
  }

  async findAll(query) {
    try {
      const { page = 1, limit = 10, ...formData } = query
      return await this.roleRepository.findAndCount({
        select: ['id', 'roleName', 'roleDesc','isSuper', 'status', 'createTime', 'updateTime'],
        where: {
          ...formData
        },
        skip: (page - 1) * limit,
        take: limit
      });
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async delete(id){
    const queryRunner = this.dataSource.createQueryRunner()
    await queryRunner.connect()
    queryRunner.startTransaction();
    try {
      queryRunner.manager.delete(Role, id)
      queryRunner.manager.delete(Auth, { roleId: id })
      queryRunner.manager.delete(RoleAdmin, { roleId: id })
      await queryRunner.commitTransaction()
      return true
    } catch (error) {
      await queryRunner.rollbackTransaction()
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    } finally {
      await queryRunner.release()
    }
  }
  /**
   * 获取角色权限列表
   * 
   * 此函数根据提供的查询参数，尤其是角色ID，来获取该角色的权限列表包括角色ID、菜单ID、状态和操作ID
   * 它首先检查查询参数中是否包含了角色ID，如果没有，则抛出一个HTTP异常
   * 如果角色ID存在，它将查询数据库，返回匹配的角色权限信息
   * 
   * @param query 查询参数对象，应包含角色ID和其他可能的筛选条件
   * @returns 返回一个Promise，解析为角色权限信息数组
   * @throws 如果缺少角色ID参数，抛出HttpException
   */
  async getRoleAuthList(query) {
    try {
      if(!query.roleId){
        throwCustomException('缺少参数')
      }
      return await this.authRepository.find({
        select: ['roleId', 'menuId', 'status', 'actionIds'],
        where: {
          ...query
        }
      });
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
  /**
   * 获取菜单角色权限
   * 
   * 该函数用于根据角色ID和菜单ID查询特定角色在特定菜单上的权限信息
   * 它首先检查提供的查询参数中是否包含必要的信息（角色ID和菜单ID），
   * 如果缺少任何一项，则抛出一个Http异常，表明缺少参数
   * 如果参数完整，它将尝试从数据库中查找对应的权限信息
   * 
   * @param query 查询参数，应包含roleId和menuId
   * @returns 返回查询到的角色权限信息，如果没有找到，则返回null
   * @throws 如果缺少参数或数据库查询过程中出现错误，抛出HttpException
   */
  async getRoleAuth(query) {
    try {
      if(!query.roleId || !query.menuId){
        throwCustomException('缺少参数')
      }
      return await this.authRepository.findOne({
        where:query
      });
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
  async isSuper(adminId){
    const roles = await this.roleAdminRepository.find({ where:{ adminId } })
    const roleIds = roles.map(r => r.roleId)
    const isSuper = await this.roleRepository.find({
      where:{ isSuper: 1, id: In(roleIds) }
    })
    return { isSuper, roleIds}
  }
  async getMenuAuthByAdmin(route: string, adminId: number) {
    try {
      if(!adminId || !route){
        throwCustomException('参数错误')
      }
      const menu = await this.menuRepository.findOne({ where:{ route } })
      if(!menu){
        throwCustomException('没有这个菜单')
        return
      }
      const menuId = menu.id
      const {isSuper} = await this.isSuper(adminId)
      if(isSuper.length > 0){
        return await this.actionRepository.find({ where:{ menuId, status: 0 } })
      }
      
      const sql = `SELECT ra.adminId, auth.menuId, auth.actionIds, auth.status 
      from n_role_admin as ra 
      left join n_role_auth as auth on ra.roleId = auth.roleId and auth.menuId = ${menuId} and status = 0
      where ra.adminId = ${adminId}`
      const roleAdmin = await this.dataSource.query(sql)
      if(roleAdmin.length > 0){
        let ids = []
        roleAdmin.forEach(r => {
          if(r.actionIds){
            const str: string = r.actionIds.slice(1, -1)
            const arr: any = str.split(',')
            ids = ids.concat(arr)
          }
          
        })
        const newArr = [...new Set(ids)]
        return await this.actionRepository.find({
          where: {
            id: In(newArr)
          }
        })
      }
      return []
      // return await this.dataSource.getRepository(RoleAdmin)
      //           .createQueryBuilder('roleAdmin')
      //           .leftJoinAndSelect('roleAdmin.auth', 'auth', 'roleAdmin.roleId = auth.roleId and auth.menuId = :menuId', {menuId})
      //           .select('roleAdmin.adminId, auth.menuId, auth.actionIds, auth.status')
      //           .where("roleAdmin.adminId = :adminId", { adminId })
      //           .getRawMany();
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async isAuthExists(obj){
    const result = await this.authRepository.findOne({ 
      where: obj
    });
    return !!result
  }
  /**
   * 异步保存角色权限信息
   * 
   * 此函数负责处理角色权限的创建或更新它首先解析传入的角色权限数据，
   * 然后检查数据库中是否已存在相应的权限信息如果存在，则更新权限信息；
   * 否则，创建新的权限信息在处理过程中，如果遇到错误，则抛出HTTP异常
   * 
   * @param createAuthDto 包含角色权限信息的DTO，包括roleId、menuId和actionIds
   * @returns 返回保存或更新后的角色权限信息
   * @throws 当发生错误时，抛出HttpException
   */
  async saveRoleAuth(createAuthDto: CreateAuthDto) {
    try{
      const { roleId, menuId, actionIds } = createAuthDto;

      const filter = { roleId, menuId };
      let result = { ...createAuthDto };
      if(actionIds){
        result.actionIds = ',' + actionIds + ','
      }
      const isExists = await this.isAuthExists(filter)
      if(isExists){
        return await this.authRepository.update(filter, result)
      }else{
        return await this.authRepository.save(result)
      }
      
    } catch (error) {
      throw new HttpException(error.message, error.status, {
        
        cause: error
      });
    }
  }
  
}
